/*
 *    Copyright © OpenAtom Foundation.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package com.inspur.edp.formserver.vmmanager.voguide;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.inspur.edp.bef.bizentity.GspBusinessEntity;
import com.inspur.edp.cef.designtime.api.util.MetadataUtil;
import com.inspur.edp.formserver.viewmodel.GspViewModel;
import com.inspur.edp.formserver.viewmodel.accessory.AccessoryService;
import com.inspur.edp.formserver.viewmodel.common.ConvertUtils;
import com.inspur.edp.formserver.viewmodel.extendinfo.api.GspVoExtendInfoService;
import com.inspur.edp.formserver.viewmodel.extendinfo.entity.GspVoExtendInfo;
import com.inspur.edp.formserver.vmmanager.accessory.ApprovalLogType;
import com.inspur.edp.formserver.vmmanager.util.CheckInfoUtil;
import com.inspur.edp.lcm.metadata.api.entity.GspMetadata;
import com.inspur.edp.lcm.metadata.api.entity.MetadataHeader;
import com.inspur.edp.metadata.rtcustomization.api.CustomizationService;
import io.iec.edp.caf.boot.context.CAFContext;
import io.iec.edp.caf.commons.utils.SpringBeanUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

public class VoGuideUtil {

  private VoGuideUtil() {
  }

  public static VoGuideUtil instance;

  public static VoGuideUtil getInstance() {
    if (instance == null) {
      return new VoGuideUtil();
    }
    return instance;
  }

  private String VOGUIDE_VO_METADATATYPE = "GSPViewModel";
  private String VOGUIDE_EXTEND_CONFIG_APPROVAL = "APPROVAL_LOG";

  // region 服务工具
  private AccessoryService accessoryService;

  private AccessoryService getAccessoryService() {
    if (accessoryService == null) {
      accessoryService = SpringBeanUtils.getBean(AccessoryService.class);
    }
    return accessoryService;
  }

  private CustomizationService customizationService;

  private CustomizationService getCustomizationService() {
    if (customizationService == null) {
      customizationService = SpringBeanUtils.getBean(CustomizationService.class);
    }
    return customizationService;
  }

  private GspVoExtendInfoService gspVoExtendInfoService;

  private GspVoExtendInfoService getGspVoExtendInfoService() {
    if (gspVoExtendInfoService == null) {
      gspVoExtendInfoService = SpringBeanUtils.getBean(GspVoExtendInfoService.class);
    }
    return gspVoExtendInfoService;
  }

  private ObjectMapper objectMapper;

  private ObjectMapper getObjectMapper() {
    if (objectMapper == null) {
      objectMapper = new ObjectMapper();
    }
    return objectMapper;
  }

  // endregion

  /**
   * 转换为Vo实体
   */
  public GspViewModel createVo(GspBusinessEntity be, HashMap<String, String> configs,
      String bePkgName, String voGenerattingAssembly) {
    GspViewModel vo = ConvertUtils
        .convertToViewModel(be, bePkgName, be.getID(), voGenerattingAssembly).clone();
    handleApprovalConfig(vo, configs);
    return vo;
  }

  /**
   * 保存Vo实体
   */
  public String saveVoRt(GspViewModel vo, String bizObjectId, String nameSpace) {
    checkBeforeSave(vo.getGeneratedConfigID(), vo.getId());
    GspMetadata metadata = new GspMetadata();
    metadata.setContent(vo);
    MetadataHeader header = createMetadataHeader(vo, bizObjectId, nameSpace);
    metadata.setHeader(header);
    getCustomizationService().save(metadata);
    // todo:LCM提供保存后扩展前，自行调用
    this.saveGspVoExtendInfo(metadata);
    return vo.getID();
  }

  /**
   * 根据BEMeta获取VOGeneratingAssembly属性
   */
  public String getVoMetaGeneratingAssembly(GspMetadata beMetadata) {
    String beNameSpace = beMetadata.getHeader().getNameSpace();
    return beNameSpace;
  }

  /**
   * 保存前校验 todo:临时仅校验运行时表中的Vo元数据,不全，不包含部署在server目录的
   */
  public void checkBeforeSave(String configId, String id) {
    GspVoExtendInfo info = this.getGspVoExtendInfoService().getVoExtendInfoByConfigId(configId);
    Boolean checkResult = info == null || info.getId().equals(id);
    if (!checkResult) {
      throw new RuntimeException("已存在ConfigId为'" + configId + "'的VO元数据，请修改VO编号");
    }
  }

  /**
   * 加载运行时元数据
   */
  public GspMetadata getRtMetadata(String metadataId) {
    CheckInfoUtil.checkNessaceryInfo("metadataId", metadataId);
    GspMetadata meta = MetadataUtil.getCustomMetadata(metadataId);
    if (meta == null || meta.getContent() == null) {
      throw new RuntimeException("调用CustomizationService加载运行时元数据失败，元数据Id=" + metadataId);
    }
    return meta;
  }

  // region 私有方法
  private void handleApprovalConfig(GspViewModel vo, HashMap<String, String> configs) {
    String config = getConfig(configs, VOGUIDE_EXTEND_CONFIG_APPROVAL);
    if (CheckInfoUtil.checkNull(config)) {
      return;
    }
    try {
      JsonNode node = getObjectMapper().readTree(config);
      JsonNode enableNode = node.get("enable");
      if (enableNode == null) {
        return;
      }
      Boolean enable = enableNode.booleanValue();
      if (!enable) {
        return;
      }
      //
      ApprovalLogType approvalLogType=getObjectMapper().readValue(node.get("approveType").asText(),ApprovalLogType.class);
      String entityCode = node.get("entity").get("code").textValue();
      String fieldLabelId = node.get("field").get("code").textValue();
      boolean includeBacklog;
      if(node.get("includeBacklog")==null){
        includeBacklog=false;
      }else {
        includeBacklog = node.get("includeBacklog").booleanValue();
      }
      addApprovalLog(vo, approvalLogType,entityCode, fieldLabelId,includeBacklog);
    } catch (JsonProcessingException e) {
      throw new RuntimeException(e);
    }
  }

  private void addApprovalLog(GspViewModel vo,ApprovalLogType approvalLogType,String entityCode ,String fieldLabelId,boolean includeBacklog){
    switch (approvalLogType){
      case ProcessInstant:
        getAccessoryService().addApprovalComments(vo,entityCode,fieldLabelId,includeBacklog);
        break;
      case BIllCode:
        getAccessoryService().addApprovalWorkItenLogs(vo,entityCode,fieldLabelId,includeBacklog);
        break;
      default:
        throw new RuntimeException("请选择有效的获取审批日志的类型");
    }
  }
  private String getConfig(HashMap<String, String> configs, String key) {
    if (!configs.containsKey(key)) {
      return "";
    }
    String config = configs.get(key);
    return config;
  }

  private MetadataHeader createMetadataHeader(GspViewModel vo, String bizObjectId,
      String nameSpace) {
    MetadataHeader header = new MetadataHeader();
    header.setId(vo.getId());
    header.setCode(vo.getCode());
    header.setName(vo.getName());
    header.setBizobjectID(bizObjectId);
    header.setNameSpace(nameSpace);
    header.setType(VOGUIDE_VO_METADATATYPE);
    return header;
  }

  private void saveGspVoExtendInfo(GspMetadata voMeta) {
    List<GspVoExtendInfo> list = new ArrayList<>();
    list.add(getVoDataExtendInfo(voMeta));
    getGspVoExtendInfoService().saveGspVoExtendInfos(list);
  }
  private GspVoExtendInfo getVoDataExtendInfo(GspMetadata voMeta) {
    GspVoExtendInfo info = new GspVoExtendInfo();
    GspViewModel vo = (GspViewModel) voMeta.getContent();
    GspVoExtendInfo infoTemp = getGspVoExtendInfoService().getVoExtendInfo(vo.getId());
    if(infoTemp==null||!vo.getGeneratedConfigID().equals(info.getConfigId())){
      info.setId(vo.getId());
      info.setConfigId(vo.getGeneratedConfigID());
      info.setBeSourceId(vo.getMapping().getTargetMetadataId());
      info.setCreatedOn(Date.from(CAFContext.current.getCurrentDateTime().toInstant()));
      info.setLastChangedOn(Date.from(CAFContext.current.getCurrentDateTime().toInstant()));
      return info;
    } else{
      infoTemp.setLastChangedOn(Date.from(CAFContext.current.getCurrentDateTime().toInstant()));
      return infoTemp;

    }

  }
  // endregion
}
